package system

import (
	"encoding/json"
	"errors"

	"gin-sns/app/ginframe/cache"
	"gin-sns/app/ginframe/db"
	"gin-sns/app/ginframe/utils/convert"
	"gin-sns/app/ginframe/utils/gconv"
	"gin-sns/app/ginframe/utils/gmd5"
	"gin-sns/app/ginframe/utils/page"
	"gin-sns/app/ginframe/utils/random"

	"gin-sns/app/model"

	"gin-sns/app/dao/monitor/online"
	"gin-sns/app/dao/system/user"
	"gin-sns/app/dao/system/user_post"
	"gin-sns/app/dao/system/user_role"

	userOnlineModel "gin-sns/app/model/monitor/online"
	userModel "gin-sns/app/model/system/user"
	userPostModel "gin-sns/app/model/system/user_post"
	userRoleModel "gin-sns/app/model/system/user_role"

	"gin-sns/app/service/middleware/sessions"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

var UserService = newUserService()

func newUserService() *userService {
	return &userService{}
}

type userService struct {
	//用户session列表
	SessionList sync.Map
}

//根据主键查询用户信息
func (s *userService) SelectRecordById(id int64) (*userModel.Entity, error) {
	entity := &userModel.Entity{UserId: id}
	have, err := user.UserDao.FindOne(entity)
	if !have {
		err = errors.New("not found")
		entity = nil
	}
	return entity, err
}

// 根据条件分页查询用户列表
func (s *userService) SelectRecordList(param *userModel.SelectPageReq) ([]userModel.UserListEntity, *page.Paging, error) {
	return user.UserDao.SelectPageList(param)
}

// 导出excel
func (s *userService) Export(param *userModel.SelectPageReq) (string, error) {
	head := []string{"用户名", "呢称", "Email", "电话号码", "性别", "部门", "领导", "状态", "删除标记", "创建人", "创建时间", "备注"}
	col := []string{"u.login_name", "u.user_name", "u.email", "u.phonenumber", "u.sex", "d.dept_name", "d.leader", "u.status", "u.del_flag", "u.create_by", "u.create_time", "u.remark"}
	return user.UserDao.SelectExportList(param, head, col)
}

//新增用户
func (s *userService) AddSave(req *userModel.AddReq, ctx *gin.Context) (int64, error) {
	var entity userModel.Entity
	entity.LoginName = req.LoginName
	entity.UserName = req.UserName
	entity.Email = req.Email
	entity.Phonenumber = req.Phonenumber
	entity.Status = req.Status
	entity.Sex = req.Sex
	entity.DeptId = req.DeptId
	entity.Remark = req.Remark

	//生成密码
	newSalt := random.GenerateSubId(6)
	newToken := req.LoginName + req.Password + newSalt
	newToken = gmd5.MustEncryptString(newToken)

	entity.Salt = newSalt
	entity.Password = newToken

	entity.CreateTime = time.Now()

	createUser := s.GetProfile(ctx)

	if createUser != nil {
		entity.CreateBy = createUser.LoginName
	}

	entity.DelFlag = "0"

	session := db.Instance().Engine().NewSession()
	err := session.Begin()

	_, err = session.Table(user.UserDao.TableName()).Insert(&entity)

	if err != nil || entity.UserId <= 0 {
		session.Rollback()
		return 0, err
	}

	//增加岗位数据
	if req.PostIds != "" {
		postIds := convert.ToInt64Array(req.PostIds, ",")
		userPosts := make([]userPostModel.Entity, 0)
		for i := range postIds {
			if postIds[i] > 0 {
				var userPost userPostModel.Entity
				userPost.UserId = entity.UserId
				userPost.PostId = postIds[i]
				userPosts = append(userPosts, userPost)
			}
		}
		if len(userPosts) > 0 {
			_, err := session.Table(user_post.UserPostDao.TableName()).Insert(userPosts)
			if err != nil {
				session.Rollback()
				return 0, err
			}
		}

	}

	//增加角色数据
	if req.RoleIds != "" {
		roleIds := convert.ToInt64Array(req.RoleIds, ",")
		userRoles := make([]userRoleModel.Entity, 0)
		for i := range roleIds {
			if roleIds[i] > 0 {
				var userRole userRoleModel.Entity
				userRole.UserId = entity.UserId
				userRole.RoleId = roleIds[i]
				userRoles = append(userRoles, userRole)
			}
		}
		if len(userRoles) > 0 {
			_, err := session.Table(user_role.UserRoleDao.TableName()).Insert(userRoles)
			if err != nil {
				session.Rollback()
				return 0, err
			}
		}
	}

	return entity.UserId, session.Commit()
}

//新增用户
func (s *userService) EditSave(req *userModel.EditReq, ctx *gin.Context) (int64, error) {
	entity := &userModel.Entity{UserId: req.UserId}
	ok, err := user.UserDao.FindOne(entity)
	if err != nil {
		return 0, err
	}
	if !ok {
		return 0, errors.New("数据不存在")
	}

	entity.UserName = req.UserName
	entity.Email = req.Email
	entity.Phonenumber = req.Phonenumber
	entity.Status = req.Status
	entity.Sex = req.Sex
	entity.DeptId = req.DeptId
	entity.Remark = req.Remark

	entity.UpdateTime = time.Now()

	updateUser := s.GetProfile(ctx)

	if updateUser != nil {
		entity.UpdateBy = updateUser.LoginName
	}

	session := db.Instance().Engine().NewSession()
	tanErr := session.Begin()

	_, tanErr = session.Table(user.UserDao.TableName()).ID(entity.UserId).Update(entity)

	if tanErr != nil {
		session.Rollback()
		return 0, tanErr
	}

	//增加岗位数据
	if req.PostIds != "" {
		postIds := convert.ToInt64Array(req.PostIds, ",")
		userPosts := make([]userPostModel.Entity, 0)
		for i := range postIds {
			if postIds[i] > 0 {
				var userPost userPostModel.Entity
				userPost.UserId = entity.UserId
				userPost.PostId = postIds[i]
				userPosts = append(userPosts, userPost)
			}
		}
		if len(userPosts) > 0 {
			session.Exec("delete from sys_user_post where user_id=?", entity.UserId)
			_, tanErr = session.Table(user_post.UserPostDao.TableName()).Insert(userPosts)
			if tanErr != nil {
				session.Rollback()
				return 0, err
			}
		}

	}

	//增加角色数据
	if req.RoleIds != "" {
		roleIds := convert.ToInt64Array(req.RoleIds, ",")
		userRoles := make([]userRoleModel.Entity, 0)
		for i := range roleIds {
			if roleIds[i] > 0 {
				var userRole userRoleModel.Entity
				userRole.UserId = entity.UserId
				userRole.RoleId = roleIds[i]
				userRoles = append(userRoles, userRole)
			}
		}
		if len(userRoles) > 0 {
			session.Exec("delete from sys_user_role where user_id=?", entity.UserId)
			_, err := session.Table(user_role.UserRoleDao.TableName()).Insert(userRoles)
			if tanErr != nil {
				session.Rollback()
				return 0, err
			}
		}
	}

	return 1, session.Commit()
}

//根据主键删除用户信息
func (s *userService) DeleteRecordById(id int64) bool {
	entity := &userModel.Entity{UserId: id}
	result, _ := user.UserDao.Delete(entity)
	if result > 0 {
		return true
	}
	return false
}

//批量删除用户记录
func (s *userService) DeleteRecordByIds(ids string) int64 {
	idarr := convert.ToInt64Array(ids, ",")
	result, _ := user.UserDao.DeleteBatch(idarr...)
	user_role.UserRoleDao.DeleteBatch(idarr...)
	user_post.UserPostDao.DeleteBatch(idarr...)
	return result
}

//判断是否是系统管理员
func (s *userService) IsAdmin(userId int64) bool {
	if userId == 1 {
		return true
	} else {
		return false
	}
}

// 判断用户是否已经登录
func (s *userService) IsSignedIn(ctx *gin.Context) bool {
	session := sessions.Default(ctx)
	uid := session.Get(model.USER_ID)
	if uid != nil {
		return true
	}
	return false
}

// 用户登录，成功返回用户信息，否则返回nil; passport应当会md5值字符串
func (s *userService) SignIn(loginnName, password string, ctx *gin.Context) (string, error) {
	//查询用户信息
	entity := userModel.Entity{LoginName: loginnName}
	ok, err := user.UserDao.FindOne(&entity)

	if err != nil {
		return "", err
	}

	if !ok {
		return "", errors.New("用户名或者密码错误")
	}

	//校验密码
	token := entity.LoginName + password + entity.Salt

	token = gmd5.MustEncryptString(token)

	if strings.Compare(entity.Password, token) == -1 {
		return "", errors.New("密码错误")
	}
	return s.SaveUserToSession(&entity, ctx), nil
}

//保存用户信息到session
func (s *userService) SaveUserToSession(user *userModel.Entity, ctx *gin.Context) string {
	session := sessions.Default(ctx)
	session.Set(model.USER_ID, user.UserId)
	tmp, _ := json.Marshal(user)
	session.Set(model.USER_SESSION_MARK, string(tmp))
	session.Save()
	sessionId := session.SessionId()
	s.SessionList.Store(sessionId, ctx)
	return sessionId
}

//清空用户菜单缓存
func (s *userService) ClearMenuCache(user *userModel.Entity) {
	if s.IsAdmin(user.UserId) {
		cache.Instance().Delete(model.MENU_CACHE)
	} else {
		cache.Instance().Delete(model.MENU_CACHE + gconv.String(user.UserId))
	}
}

// 用户注销
func (s *userService) SignOut(ctx *gin.Context) error {
	user := s.GetProfile(ctx)
	if user != nil {
		s.ClearMenuCache(user)
	}
	session := sessions.Default(ctx)
	sessionId := session.SessionId()

	s.SessionList.Delete(sessionId)
	entity := userOnlineModel.Entity{Sessionid: sessionId}
	online.UserOnlineDao.Delete(&entity)

	session.Delete(model.USER_ID)
	session.Delete(model.USER_SESSION_MARK)
	return session.Save()
}

//强退用户
func (s *userService) ForceLogout(sessionId string) error {
	var tmp interface{}
	if v, ok := s.SessionList.Load(sessionId); ok {
		tmp = v
	}

	if tmp != nil {
		ctx := tmp.(*gin.Context)
		if ctx != nil {
			s.SignOut(ctx)
			s.SessionList.Delete(sessionId)
			entity := userOnlineModel.Entity{Sessionid: sessionId}
			online.UserOnlineDao.Delete(&entity)
		}
	}

	return nil
}

// 检查账号是否符合规范,存在返回false,否则true
func (s *userService) CheckPassport(loginName string) bool {
	entity := userModel.Entity{LoginName: loginName}
	if ok, err := user.UserDao.FindOne(&entity); err != nil || !ok {
		return false
	} else {
		return true
	}
}

// 检查登陆名是否存在,存在返回true,否则false
func (s *userService) CheckNickName(userName string) bool {
	entity := userModel.Entity{UserName: userName}
	if ok, err := user.UserDao.FindOne(&entity); err != nil || !ok {
		return false
	} else {
		return true
	}
}

// 检查登陆名是否存在,存在返回true,否则false
func (s *userService) CheckLoginName(loginName string) bool {
	entity := userModel.Entity{LoginName: loginName}
	if ok, err := user.UserDao.FindOne(&entity); err != nil || !ok {
		return false
	} else {
		return true
	}
}

// 获得用户信息详情
func (s *userService) GetProfile(ctx *gin.Context) *userModel.Entity {
	session := sessions.Default(ctx)
	if session == nil {
		return nil
	}

	tmp := session.Get(model.USER_SESSION_MARK)
	str := tmp.(string)
	var u userModel.Entity
	err := json.Unmarshal([]byte(str), &u)
	if err != nil {
		return nil
	}
	return &u
}

//更新用户信息详情
func (s *userService) UpdateProfile(profile *userModel.ProfileReq, ctx *gin.Context) error {
	entity := s.GetProfile(ctx)

	if profile.UserName != "" {
		entity.UserName = profile.UserName
	}

	if profile.Email != "" {
		entity.Email = profile.Email
	}

	if profile.Phonenumber != "" {
		entity.Phonenumber = profile.Phonenumber
	}

	if profile.Sex != "" {
		entity.Sex = profile.Sex
	}

	_, err := user.UserDao.Update(entity)
	if err != nil {
		return errors.New("保存数据失败")
	}

	s.SaveUserToSession(entity, ctx)
	return nil
}

//更新用户头像
func (s *userService) UpdateAvatar(avatar string, ctx *gin.Context) error {
	entity := s.GetProfile(ctx)

	if avatar != "" {
		entity.Avatar = avatar
	}

	_, err := user.UserDao.Update(entity)
	if err != nil {
		return errors.New("保存数据失败")
	}

	s.SaveUserToSession(entity, ctx)
	return nil
}

//修改用户密码
func (s *userService) UpdatePassword(profile *userModel.PasswordReq, ctx *gin.Context) error {
	entity := s.GetProfile(ctx)

	if profile.OldPassword == "" {
		return errors.New("旧密码不能为空")
	}

	if profile.NewPassword == "" {
		return errors.New("新密码不能为空")
	}

	if profile.Confirm == "" {
		return errors.New("确认密码不能为空")
	}

	if profile.NewPassword == profile.OldPassword {
		return errors.New("新旧密码不能相同")
	}

	if profile.Confirm != profile.NewPassword {
		return errors.New("确认密码不一致")
	}

	//校验密码
	token := entity.LoginName + profile.OldPassword + entity.Salt
	token = gmd5.MustEncryptString(token)

	if token != entity.Password {
		return errors.New("原密码不正确")
	}

	//新校验密码
	newSalt := random.GenerateSubId(6)
	newToken := entity.LoginName + profile.NewPassword + newSalt
	newToken = gmd5.MustEncryptString(newToken)

	entity.Salt = newSalt
	entity.Password = newToken

	_, err := user.UserDao.Update(entity)
	if err != nil {
		return errors.New("保存数据失败")
	}

	s.SaveUserToSession(entity, ctx)
	return nil
}

//重置用户密码
func (s *userService) ResetPassword(params *userModel.ResetPwdReq) (bool, error) {
	entity := userModel.Entity{UserId: params.UserId}
	if ok, err := user.UserDao.FindOne(&entity); err != nil || !ok {
		return false, errors.New("用户不存在")
	}
	//新校验密码
	newSalt := random.GenerateSubId(6)
	newToken := entity.LoginName + params.Password + newSalt
	newToken = gmd5.MustEncryptString(newToken)

	entity.Salt = newSalt
	entity.Password = newToken
	if _, err := user.UserDao.Update(&entity); err != nil {
		return false, errors.New("保存数据失败")
	}
	return true, nil
}

//校验密码是否正确
func (s *userService) CheckPassword(user *userModel.Entity, password string) bool {
	if user == nil || user.UserId <= 0 {
		return false
	}

	//校验密码
	token := user.LoginName + password + user.Salt
	token = gmd5.MustEncryptString(token)

	if strings.Compare(token, user.Password) == 0 {
		return true
	} else {
		return false
	}
}

//检查邮箱是否已使用
func (s *userService) CheckEmailUnique(userId int64, email string) bool {
	return user.UserDao.CheckEmailUnique(userId, email)
}

//检查邮箱是否存在,存在返回true,否则false
func (s *userService) CheckEmailUniqueAll(email string) bool {
	return user.UserDao.CheckEmailUniqueAll(email)
}

//检查手机号是否已使用,存在返回true,否则false
func (s *userService) CheckPhoneUnique(userId int64, phone string) bool {
	return user.UserDao.CheckPhoneUnique(userId, phone)
}

//检查手机号是否已使用 ,存在返回true,否则false
func (s *userService) CheckPhoneUniqueAll(phone string) bool {
	return user.UserDao.CheckPhoneUniqueAll(phone)
}

//根据登陆名查询用户信息
func (s *userService) SelectUserByLoginName(loginName string) (*userModel.Entity, error) {
	return user.UserDao.SelectUserByLoginName(loginName)
}

//根据手机号查询用户信息
func (s *userService) SelectUserByPhoneNumber(phonenumber string) (*userModel.Entity, error) {
	return user.UserDao.SelectUserByPhoneNumber(phonenumber)
}

// 查询已分配用户角色列表
func (s *userService) SelectAllocatedList(roleId int64, loginName, phonenumber string) ([]userModel.Entity, error) {
	return user.UserDao.SelectAllocatedList(roleId, loginName, phonenumber)
}

// 查询未分配用户角色列表
func (s *userService) SelectUnallocatedList(roleId int64, loginName, phonenumber string) ([]userModel.Entity, error) {
	return user.UserDao.SelectUnallocatedList(roleId, loginName, phonenumber)
}
